/*
 * Copyright (c) 2007-2008, Thomas Krause (tho.krause@gmail.com)
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of gidoo nor the names of its contributors may be used to
 *       endorse or promote products derived from this software without specific
 *       prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.gidoo.cms.editor.history;

import java.text.DateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.jcr.Node;
import javax.jcr.RepositoryException;
import javax.jcr.version.Version;
import javax.jcr.version.VersionIterator;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.ajax.markup.html.AjaxLink;
import org.apache.wicket.markup.html.basic.Label;
import org.apache.wicket.markup.html.form.Form;
import org.apache.wicket.markup.html.link.Link;
import org.apache.wicket.markup.html.list.ListItem;
import org.apache.wicket.markup.html.list.ListView;
import org.apache.wicket.markup.html.panel.Panel;
import org.apache.wicket.model.Model;
import org.gidoo.cms.login.GidooCMSSession;
import org.gidoo.cms.editor.EditorPage;
import org.gidoo.cms.helper.Tools;
import org.gidoo.cms.jcr.JcrHelper;
import org.gidoo.wickettools.MessageBox;
import org.gidoo.wickettools.XHTMLDiff;

/**
 *
 * @author thomas
 */
public class HistoryPanel extends Panel
{
  
  EditorPage parentPage;
  String pagePath;
  
  ListView lsvRevisions;
  List<Version> history;
  
  public HistoryPanel(String id, Node page, EditorPage parent)
  {
    super(id);
    try
    {
      if(page == null)
      {
        this.pagePath = null;
      }
      else
      {  
        this.pagePath = page.getPath().substring(1);
      }
      this.parentPage = parent;

      Form formMain = new Form("formMain");

      history = new ArrayList<Version>();
      if(page != null)
      {
        VersionIterator it = page.getVersionHistory().getAllVersions();
        while(it.hasNext())
        {
          Version v = it.nextVersion();
          history.add(v);
        }
      }


      lsvRevisions = new ListView("lsvRevisions", history)
      {

        @Override
        protected void populateItem(ListItem item)
        {
          try
          {
            final Version rev = history.get(item.getIndex());
            final Version prev = item.getIndex() > 0 ? history.get(item.getIndex() - 1) : null;


            Link lnkDiffPrev = new Link("lnkDiffPrev")
            {

              @Override
              public void onClick()
              {
                try
                {
                  diffToPrevious(rev.getNode("jcr:frozenNode"), prev.getNode("jcr:frozenNode"));
                }
                catch(RepositoryException ex)
                {
                  Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
                  error(getString("jcrerror"));
                }
              }
            };
            lnkDiffPrev.setVisible(item.getIndex() > 0);
            item.add(lnkDiffPrev);

            item.add(new Link("lnkDiffCur")
            {

              @Override
              public void onClick()
              {
                try
                {
                  diffToCurrent(rev.getNode("jcr:frozenNode"));
                }
                catch(RepositoryException ex)
                {
                  Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
                  error(getString("jcrerror"));
                }
              }
            });
            DateFormat d = DateFormat.getDateTimeInstance();
            String ds = getString("unknown");

            if(rev.getCreated() != null)
            {
              Date date = new Date(rev.getCreated().getTimeInMillis());
              ds = d.format(date);
            }
            item.add(new Label("lblDate", new Model(ds)));

            String author = getString("unknown");
            Node revNode = rev.getNode("jcr:frozenNode");
            if(revNode.hasProperty("cms:editor"))
            {
              author = revNode.getProperty("cms:editor").getString();
            }
            item.add(new Label("lblAuthor", new Model(author)));

            item.add(new AjaxLink("lnkRestore")
            {

              @Override
              public void onClick(AjaxRequestTarget target)
              {
                try
                {
                  restore(rev);
                  info(getString("waitingforpublisher"));
                }
                catch(RepositoryException ex)
                {
                  Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
                  error(getString("jcrerror"));
                }
                
                target.addComponent(parentPage.getFeedbackPanel());
              }
            });
          }
          catch(RepositoryException ex)
          {
            Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
            error(getString("jcrerror"));
          }
        }
      };
      formMain.add(lsvRevisions);

      add(formMain);
      if(page == null)
      {
        formMain.setVisible(false);
      }
    }
    catch(RepositoryException ex)
    {
      Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
  }
  
  
  private void restore(Version oldRev) throws RepositoryException
  {
    Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();
    Node draftsNode = rootNode.getNode("drafts");
    if(oldRev != null && pagePath != null && rootNode.hasNode(pagePath))
    { 
      String name = Tools.path2DraftName(pagePath);
      // delete old unpublished version if necessary
      if(draftsNode.hasNode(name))
      {
        draftsNode.getNode(name).remove();
      }
      
      Node p = rootNode.getNode(pagePath);
      Node newDraft = draftsNode.addNode(name, p.getPrimaryNodeType().getName());
      
      Node oldRevAsNode = oldRev.getNode("jcr:frozenNode");
      
      JcrHelper.copyPageProperties(oldRevAsNode, newDraft);
      draftsNode.save();
    }
  }
  
  private void diffToCurrent(Node old) throws RepositoryException
  {

    Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();

    if(pagePath == null || !rootNode.hasNode(pagePath))
    {
      error(getString("error"));
      return;
    }

    Node page = rootNode.getNode(pagePath);

    if(!old.hasProperty("cms:xml") || !old.hasProperty("cms:title"))
    {
      warn(getString("emptyxml"));
      return;
    }
    
    String diff = XHTMLDiff.doDiff(old.getProperty("cms:xml").getString(), page.getProperty("cms:xml").getString());

    String msg = "<p>" + getString("oldtitle") + old.getProperty("cms:title").getString() + "<br />" + getString("newtitle") + page.getProperty("cms:title").getString() + "</p>" + "<table style=\"width:100%; text-align:left;\" >" + "<tr>" + "<th>" + getString("old") + "</th>" + "<th>" + getString("current") + "</th>" + "</tr>" + diff + "</table>";

    MessageBox msgBox = new MessageBox(getString("diffoldcurrent"), msg, true, MessageBox.MessageBoxButtons.OK, parentPage, null);

    setResponsePage(msgBox);
  }
 
  private void diffToPrevious(Node revNewer, Node revOlder) throws RepositoryException
  {
    Node rootNode = ((GidooCMSSession) getSession()).getJcrRootNode();

    if(pagePath == null || !rootNode.hasNode(pagePath) || revNewer == null || revOlder == null)
    {
      error(getString("error"));
      return;
    }
    
    if(!revNewer.hasProperty("cms:xml") || !revNewer.hasProperty("cms:title")
      || !revOlder.hasProperty("cms:xml") || !revOlder.hasProperty("cms:title"))
    {
      warn(getString("emptyxml"));
      return;
    }
    
    String diff = XHTMLDiff.doDiff(revOlder.getProperty("cms:xml").getString(), revNewer.getProperty("cms:xml").getString());

    String msg = "<p>" + getString("oldtitle") + revOlder.getProperty("cms:title").getString() + "<br />" + getString("newtitle") + revNewer.getProperty("cms:title").getString() + "</p>" + "<table style=\"width:100%; text-align:left;\";>" + "<tr>" + "<th>" + getString("older") + "</th>" + "<th>" + getString("newer") + "</th>" + "</tr>" + diff + "</table>";

    MessageBox msgBox = new MessageBox(getString("diffoldcurrent"), msg, true, MessageBox.MessageBoxButtons.OK, parentPage, null);

    setResponsePage(msgBox);
  }
  
  
  public void updateDataAndView(Node page, EditorPage parent)
  {
    try
    {
      if(parent == null)
      {
        throw new NullPointerException();
      }
      this.pagePath = page == null ? null : page.getPath().substring(1);
      this.parentPage = parent;

      this.history = new ArrayList<Version>();
      if(page != null)
      {
        VersionIterator it = page.getVersionHistory().getAllVersions();
        while(it.hasNext())
        {
          Version v = it.nextVersion();
          history.add(v);
        }
      }
      
      lsvRevisions.setList(history);
    }
    catch(RepositoryException ex)
    {
      Logger.getLogger(HistoryPanel.class.getName()).log(Level.SEVERE, null, ex);
      error(getString("jcrerror"));
    }
  }
}
